home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / win / rtfhelp.zip / RTFHPARS.C < prev    next >
Text File  |  1994-11-06  |  17KB  |  507 lines

  1. /*
  2. ======================================================================
  3.    RTFHelp Windows Help Generation Tool
  4.    (C) Copyright 1994 by J. Hlavaty
  5.  
  6.    RTFHPars.c
  7.    This routine parses the lines of the HDC file
  8. ======================================================================
  9. */
  10.  
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include "rtfhelp.h"
  15.  
  16. int Tokenize( FILE *flInput, FILE *flOutput, char *pLine )
  17. {
  18.   char *ptrTokenStart, *ptrTokenNext, *ptrStartOfLine ;
  19.   char *ptrTmp ;
  20.   int   lenCmd, i ;
  21.   int   idCmd, rc ;
  22.   char  strCmd[45], *strHasCRLF ;
  23.   BOOL  bNoSpace = FALSE ;
  24.   struct COMMANDENTRY *pCommandTable = &CommandList[0] ;
  25.  
  26. static char *WhiteSpace = " " ;
  27. // certain languages (such as Finnish) can have long words so give
  28. //   plenty of room
  29. static char    strTagHeader[255] ;
  30. static char    strTagTrailer[255] ;
  31. static int     multipass = FALSE ;
  32.  
  33.   // get line of text passed in...
  34.   ptrStartOfLine = pLine ;
  35.  
  36.   // if text is a non-ANSI code page (currently only 850 is supported)
  37.   //    then convert to ANSI
  38.   if (codepage)
  39.      TranslateCPToANSI( codepage, ptrStartOfLine ) ;
  40.  
  41.   // reset pointer to text passed in...
  42.   ptrTokenStart = pLine ;
  43.  
  44. // NOTE:  first call to strtok() will strip off leading delimiters...
  45.   if ( NULL == ( ptrTokenNext = strtok( ptrStartOfLine, WhiteSpace ) ) )
  46.      return INTERNAL_ERROR ;
  47.  
  48.   // skip any leading spaces...
  49.   ptrStartOfLine = ptrTokenNext ;
  50.  
  51.   // validate that the length of the line (without initial spaces)
  52.   //   is within the bounds of our buffer (including null terminator)
  53.   lenCmd = strlen(ptrTokenNext) ;
  54.  
  55.   if ( ( lenCmd + 1 ) > sizeof ( strCmd ) )
  56.   {
  57.      return INTERNAL_ERROR ;
  58.   }
  59.  
  60.   // copy parsed command, if any (we won't know until we check against our
  61.   //   table of commands).  This first command may in fact be just raw text
  62.   strcpy( strCmd, ptrTokenNext ) ;
  63.  
  64.   // does our command string have a CRLF (newline)?  It can if it's the
  65.   //   only thing on a line (i.e., the tag has no arguments)
  66.   if ( strHasCRLF = strstr( strCmd, "\n" ) )
  67.   {
  68.      *strHasCRLF = '\0' ; // remove newline
  69.      lenCmd-- ;           // subtract newline from command length count...
  70.   }
  71.  
  72.    // ignore a blank line (the newline converted to a NULLCHAR above)
  73.   if ('\0' == strCmd[0])
  74.   {
  75.      return RC_OK ;
  76.  
  77.   }
  78.  
  79.   // move ptr to next potential token...
  80.   ptrTokenNext += lenCmd ;
  81.  
  82.   // step over NULLCHAR strtok() inserted...
  83.   ptrTokenNext++ ;
  84.  
  85.   // ptrTokenNext now points at a command's args
  86.   //   ignore leading spaces...
  87.   while ( ' ' == *ptrTokenNext )
  88.      ptrTokenNext++ ;
  89.  
  90.   bNoSpace = FALSE ;
  91.  
  92.   // assume that our line is plaintext (raw text), unless we know otherwise
  93.   idCmd = plaintext ;
  94.  
  95. // notice that all of the following (within #if 0/#else) can be replaced
  96. //   with just a few short lines of code.  Readability is greatly reduced,
  97. //   however.  Use whichever you prefer (the collection of ifs can sometimes
  98. //   be easier to debug if you're changing the parser)
  99. #if 0                   // 0 = use for loop, 1 = use ifs
  100.   i ;                   // get rid of unused local variable msg
  101.  
  102.   if ('*' == pLine[0])  // comment chars must be first character on a line
  103.      idCmd = comment ;
  104.   if (';' == pLine[0])
  105.      idCmd = comment ;
  106.   if (!strcmp(strCmd,"BOLD"))
  107.      idCmd = bold ;
  108.   if (!strcmp(strCmd,"BUILD"))
  109.      idCmd = build ;
  110.   if (!strcmp(strCmd,"CONTEXTID"))
  111.      idCmd = contextID ;
  112.   if (!strcmp(strCmd,"TITLE"))
  113.      idCmd = title ;
  114.   if (!strcmp(strCmd,"KEYWORD"))
  115.      idCmd = keyword ;
  116.   if (!strcmp(strCmd,"BROWSESEQ"))
  117.      idCmd = browseseq ;
  118.   if (!strcmp(strCmd,"XREF"))
  119.      idCmd = putlink ;
  120.   if (!strcmp(strCmd,"PUTLINK"))
  121.      idCmd = putlink ;
  122.   if (!strcmp(strCmd,"DEFINITION"))
  123.      idCmd = putpopup ;
  124.   if (!strcmp(strCmd,"PUTPOPUP"))
  125.      idCmd = putpopup ;
  126.   if (!strcmp(strCmd,"XREFID"))
  127.      idCmd = xrefID ;
  128.   if (!strcmp(strCmd,"XREFCONTEXT"))
  129.      idCmd = definepopup ;
  130.   if (!strcmp(strCmd,"DEFINEPOPUP")) // for definitions
  131.      idCmd = definepopup ;
  132.   if (!strcmp(strCmd,"LINKCONTEXT"))
  133.      idCmd = definelink ;
  134.   if (!strcmp(strCmd,"DEFINELINK"))
  135.      idCmd = definelink ;
  136.   if (!strcmp(strCmd,"PAGE"))
  137.      idCmd = newpage ;
  138.   if (!strcmp(strCmd,"PARA"))
  139.      idCmd = newparagraph ;
  140.   if (!strcmp(strCmd,"DEFFONT"))
  141.      idCmd = deffont ;
  142.   if (!strcmp(strCmd,"FONTSIZE"))
  143.      idCmd = fontsize ;
  144.   if (!strcmp(strCmd,"FONT"))
  145.      idCmd = font ;
  146.   if (!strcmp(strCmd,"LEFT"))
  147.      idCmd = leftalign ;
  148.   if (!strcmp(strCmd,"CENTER"))
  149.      idCmd = centeralign ;
  150.   if (!strcmp(strCmd,"RIGHT"))
  151.      idCmd = rightalign ;
  152.   if (!strcmp(strCmd,"JUST"))
  153.      idCmd = justified ;
  154.   if (!strcmp(strCmd,"MARGL"))
  155.      idCmd = marginleft ;
  156.   if (!strcmp(strCmd,"MARGR"))
  157.      idCmd = marginright ;
  158.   if (!strcmp(strCmd,"MARGT"))
  159.      idCmd = margintop ;
  160.   if (!strcmp(strCmd,"MARGB"))
  161.      idCmd = marginbottom ;
  162.   if (!strcmp(strCmd,"DEFTAB"))
  163.      idCmd = deftab ;
  164.   if (!strcmp(strCmd,"TX"))
  165.      idCmd = tabpos ;
  166.   if (!strcmp(strCmd,"TQR"))
  167.      idCmd = tabright ;
  168.   if (!strcmp(strCmd,"TQC"))
  169.      idCmd = tabcenter ;
  170.   if (!strcmp(strCmd,"TQDEC"))
  171.      idCmd = tabdec ;
  172.   if (!strcmp(strCmd,"TB"))
  173.      idCmd = tabbar ;
  174.   if (!strcmp(strCmd,"SA"))
  175.      idCmd = spaceafter ;
  176.   if (!strcmp(strCmd,"SB"))
  177.      idCmd = spacebefore ;
  178.   if (!strcmp(strCmd,"SL"))
  179.      idCmd = spacebetween ;
  180.   if (!strcmp(strCmd,"FIRSTINDENT"))
  181.      idCmd = firstlineindent ;
  182.   if (!strcmp(strCmd,"LEFTINDENT"))
  183.      idCmd = leftindent ;
  184.   if (!strcmp(strCmd,"RIGHTINDENT"))
  185.      idCmd = rightindent ;
  186.   if (!strcmp(strCmd,"LINE"))
  187.      idCmd = requiredlinebreak ;
  188.   if (!strcmp(strCmd,"TAB"))
  189.      idCmd = tab ;
  190.   if (!strcmp(strCmd,"DEFFORMAT"))
  191.      idCmd = defformat ;
  192.   if (!strcmp(strCmd,"BMC"))
  193.      idCmd = bitmapcharacter ;
  194.   if (!strcmp(strCmd,"BOX"))
  195.      idCmd = box ;
  196.   if (!strcmp(strCmd,"PARD"))
  197.      idCmd = pard ;
  198.   if (!strcmp(strCmd,"FOREGROUNDCOLOR"))
  199.      idCmd = foregroundcolor ;
  200.   if (!strcmp(strCmd,"PLAIN"))
  201.      idCmd = plain ;
  202.   if (!strcmp(strCmd,"ITALIC"))
  203.      idCmd = italic ;
  204.   if (!strcmp(strCmd,"SMALLCAPS"))
  205.      idCmd = smallcaps ;
  206.   if (!strcmp(strCmd,"SPACECHAR"))
  207.      idCmd = spacechar ;
  208.   if (!strcmp(strCmd,"KEEP"))
  209.      idCmd = keep ;
  210.   if (!strcmp(strCmd,"KEEPNEXT"))
  211.      idCmd = keepnext ;
  212. #else
  213.    if ( ('*' == pLine[0]) ||  // comment chars must be
  214.         (';' == pLine[0]) )   //   first character on a line
  215.    {
  216.       idCmd = comment ;       // no need to check table
  217.    }
  218.    else                       // this way shrinks the executable by more than 1K!
  219.    {  // for all commands in the table...
  220.       for (i=0; i < NOOFCMDS ; i++)
  221.       {  // is our command string the same as the string in this entry
  222.          //    of the command table (note that case is preserved during the test)
  223.          if ( !strcmp( strCmd, pCommandTable[i].strCmd ) )
  224.          {
  225.             // yes, we found our command
  226.             idCmd = pCommandTable[i].idCmd ; // OK, remember ID
  227.  
  228.             if ( comment == idCmd )
  229.             {
  230.                // in case the user put spaces before a * or ; we must
  231.                //   make sure that such a situation is not caught here
  232.                //   as a comment.  It is plain text as a comment character
  233.                //   MUST begin on column 1.  Another option would have
  234.                //   been to update the table to put comments as id plaintext
  235.                //   as they are caught outside the 'for' loop in any case...
  236.                idCmd = plaintext ;
  237.             }
  238.             break ;                          //   and stop checking...
  239.          }
  240.       }
  241.    }
  242. #endif
  243.  
  244.   // clear out any previous header or trailer text
  245.   strTagHeader[0] = '\0' ;
  246.   strTagTrailer[0] = '\0' ;
  247.  
  248.   if ( (idCmd != plaintext) &&
  249.        (idCmd != comment)   &&
  250.        (TRUE == bVerbose) )
  251.   {  // only inform user about tags (except comments), not raw text
  252.      printf( "Processing %s...\n", strCmd ) ;
  253.   }
  254.  
  255.   switch(idCmd) {
  256.     case build:            // build tag*
  257.       strcpy(strTagHeader,"*{\\footnote ") ;
  258.       strcpy(strTagTrailer, "}") ;
  259.       break ;
  260.     case title:            // topic title*
  261.       strcpy(strTagHeader,"${\\footnote ") ;
  262.       strcpy(strTagTrailer, "}") ;
  263.       break;
  264.     case keyword:          // keyword*
  265.       strcpy(strTagHeader,"K{\\footnote ") ;
  266.       strcpy(strTagTrailer, "}") ;
  267.       break ;
  268.     case browseseq:        // browse sequence identifier*
  269.       strcpy(strTagHeader,"+{\\footnote ") ;
  270.       strcpy(strTagTrailer, "}") ;
  271.       break;
  272.     case putlink:          // hot spot -- links another topic*
  273.       strcpy(strTagHeader,"{\\uldb") ;
  274.       strcpy(strTagTrailer, "}") ;
  275.       break ;
  276.     case putpopup:         // link to a popup topic*
  277.       strcpy(strTagHeader,"{\\ul") ; // space is removed in new version
  278.       strcpy(strTagTrailer, "}") ;       //   but notice we DO have one before the tag
  279.       break ;                            //   so it won't be underlined
  280.     case xrefID:           // creates a link to topic w. context string*
  281.       strcpy(strTagHeader,"{\\v") ; // remove extra space (user must add space bet. keyword and arg)
  282.       strcpy(strTagTrailer, "}") ;
  283.       break ;
  284.     case definepopup:      // specifies a context string ( = definelink)*
  285.       strcpy(strTagHeader,"\\page #{\\footnote ") ;
  286.       strcpy(strTagTrailer, "}") ;
  287.       break;
  288.     case definelink:       // specifies a context string ( = definepopup)*
  289.       strcpy(strTagHeader,"#{\\footnote ") ;
  290.       strcpy(strTagTrailer, "}") ;
  291.       break;
  292.     case bold:             // starts bold text*
  293.       strcpy(strTagHeader,"{\\b") ; // remove space
  294.       strcpy(strTagTrailer, "}") ;
  295.       break ;
  296.     case comment:
  297.       return RC_OK ;                   // ignore this line, it's a comment
  298.       break;
  299.     case newpage:          // marks the end of a topic*
  300.       strcpy(strTagHeader,"\\page") ;
  301.       *ptrStartOfLine = '\0' ;         // zero out text
  302.       ptrTokenNext = ptrStartOfLine ;
  303.       bNoSpace = TRUE ;
  304.       break ;
  305.     case newparagraph:     // marks end of a paragraph*
  306.       strcpy(strTagHeader,"\\par") ;
  307.       *ptrStartOfLine = '\0' ;         // zero out text
  308.       ptrTokenNext = ptrStartOfLine ;
  309.       bNoSpace = TRUE ;
  310.       break ;
  311.     case leftalign:
  312.     case centeralign:
  313.     case rightalign:
  314.     case justified:
  315.                            // aligns text along left/center/right indent
  316.                            //    or justified*
  317.       if (leftalign == idCmd)
  318.          strcpy(strTagHeader,"\\par\\ql") ;
  319.       if (centeralign == idCmd)
  320.          strcpy(strTagHeader,"\\par\\qc") ;
  321.       if (rightalign == idCmd)
  322.          strcpy(strTagHeader,"\\par\\qr") ;
  323.       if (justified == idCmd)
  324.          strcpy(strTagHeader,"\\par\\qj") ;
  325.  
  326.       *ptrStartOfLine = '\0' ;         // zero out text
  327.  
  328.       ptrTokenNext = ptrStartOfLine ;
  329.       bNoSpace = TRUE ;
  330.       break ;
  331.     case deffont:          // sets default font number (from font table)*
  332.       strcpy(strTagHeader,"\\deff") ;  // note: no space after 'deff'
  333.       bNoSpace = TRUE ;
  334.       break ;
  335.     case fontsize:         // sets the size of the font*
  336.       strcpy(strTagHeader,"\\fs") ;    // note there is no space after 'fs'
  337.       bNoSpace = TRUE ;
  338.       break ;
  339.     case font:             // sets the font number (from font table)*
  340.       strcpy(strTagHeader,"\\f") ;     // note there is no space after 'f'
  341.       bNoSpace = TRUE ;
  342.       break ;
  343. /*
  344.  *  case marginleft:
  345.  *    strcpy(strTagHeader,"\\margl") ;
  346.  *    bNoSpace = TRUE ;
  347.  *    break ;
  348.  *  case marginright:
  349.  *    strcpy(strTagHeader,"\\margr") ;
  350.  *    bNoSpace = TRUE ;
  351.  *    break;
  352.  *  case margintop:
  353.  *    strcpy(strTagHeader,"\\margt") ;
  354.  *    bNoSpace = TRUE ;
  355.  *    break;
  356.  *  case marginbottom:
  357.  *    strcpy(strTagHeader,"\\margb") ;
  358.  *    bNoSpace = TRUE ;
  359.  *    break;
  360. */
  361.     case deftab:
  362.       strcpy(strTagHeader,"\\deftab") ;
  363.       bNoSpace = TRUE ;
  364.       break;
  365.     case tabpos:           // sets position of a tab stop*
  366.       strcpy(strTagHeader,"\\tx") ;
  367.       bNoSpace = TRUE ;
  368.       break;
  369.     case tabright:         // advances to next tab stop, aligns text right*
  370.       strcpy(strTagHeader,"\\tqr") ;
  371.       bNoSpace = TRUE ;
  372.       break;
  373.     case tabcenter:        // advances to next tab stop, centers text*
  374.       strcpy(strTagHeader,"\\tqc") ;
  375.       bNoSpace = TRUE ;
  376.       break;
  377.     case tabdec:
  378.       strcpy(strTagHeader,"\\tqdec") ;
  379.       bNoSpace = TRUE ;
  380.       break;
  381.     case tabbar:           // advances to next tab stop*
  382.       strcpy(strTagHeader,"\\tb") ;
  383.       bNoSpace = TRUE ;
  384.       break;
  385.     case spaceafter:       // sets amount of vertical spacing after paragraph*
  386.       strcpy(strTagHeader,"\\sa") ;
  387.       bNoSpace = TRUE ;
  388.       break;
  389.     case spacebefore:      // sets amount of vertical spacing before paragraph*
  390.       strcpy(strTagHeader,"\\sb") ;
  391.       bNoSpace = TRUE ;
  392.       break;
  393.     case spacebetween:     // sets amount of vert. spacing betw. lines of para.*
  394.       strcpy(strTagHeader,"\\sl") ;
  395.       bNoSpace = TRUE ;
  396.       break;
  397.     case requiredlinebreak: // breaks current line without ending paragraph*
  398.       strcpy(strTagHeader,"\\line") ;
  399.       bNoSpace = TRUE ;
  400.       break;
  401.     case tab:              // inserts a tab character*
  402.       strcpy(strTagHeader,"\\tab") ;
  403.       bNoSpace = TRUE ;
  404.       break;
  405.     case defformat:
  406.       strcpy(strTagHeader,"\\defformat") ;
  407.       bNoSpace = TRUE ;
  408.       break;
  409.     case firstlineindent:  // sets first-line indent for paragraph*
  410.       strcpy(strTagHeader,"\\fi") ;
  411.       bNoSpace = TRUE ;
  412.       break ;
  413.     case leftindent:       // sets left indent for the paragraph*
  414.       strcpy(strTagHeader,"\\li") ;
  415.       bNoSpace = TRUE ;
  416.       break;
  417.     case rightindent:      // sets the right indent for the paragraph*
  418.       strcpy(strTagHeader,"\\ri") ;
  419.       bNoSpace = TRUE ;
  420.       break;
  421.     case bitmapcharacter:  // displays specified bitmap or metafile in
  422.                            //   current line of text*
  423.       strcpy(strTagHeader,"\\{bmc") ; // note that this is NOT an RTF tag!
  424.       strcpy(strTagTrailer, "\\}") ;
  425.       bNoSpace = FALSE ;
  426.       break;
  427.     case box:              // draws a box around the current paragraph/pict.*
  428.       strcpy(strTagHeader,"\\box") ;
  429.       bNoSpace = TRUE ;
  430.       break;
  431.     case foregroundcolor:  // sets foreground color*
  432.       strcpy(strTagHeader,"\\cf") ; // note that this requires colortable support
  433.       break;
  434.     case pard:             // restores para. properties to default values*
  435.       strcpy(strTagHeader,"\\pard") ;
  436.       break;
  437.  
  438.     case plain:            // restores character properties to default values*
  439.       strcpy(strTagHeader,"\\plain") ;
  440.       break;
  441.     case italic:           // starts italic text*
  442.       strcpy(strTagHeader,"{\\i") ;
  443.       strcpy(strTagTrailer, "}") ;
  444.       break;
  445.  
  446.     case smallcaps:        // starts small-capital text*
  447.       strcpy(strTagHeader,"{\\scaps") ;
  448.       strcpy(strTagTrailer, "}") ;
  449.       break;
  450.  
  451.     case spacechar:
  452.       strcpy(strTagHeader,"") ;
  453.       strcpy(strTagTrailer, "") ;
  454.       hardspace = *ptrTokenNext ;      // set hardspace (non-stripable initial whitespace)
  455.       if ('\n' == hardspace)
  456.          hardspace == '%' ;            // reset hardspace character to default
  457.       return RC_OK ;                   // generate no output file text for this tag
  458.       break;
  459.     case keepnext:         // creates non-scrolling rgn at top of help window*
  460.       strcpy(strTagHeader,"\\keepn") ;
  461.       bNoSpace = TRUE ;
  462.       break;               // prevents WinHelp from wrapping text to fit help wnd*
  463.     case keep:
  464.       strcpy(strTagHeader,"\\keep") ;
  465.       bNoSpace = TRUE ;
  466.       break;
  467.  
  468.  
  469.     default: // this is 'plaintext' type...
  470.       *(ptrStartOfLine+lenCmd) = ' ' ; // put the space we removed back..
  471.       bNoSpace = TRUE ;
  472.       ptrTokenNext = &pLine[0] ;       //   and prepare to write the entire string out...
  473.     }
  474.  
  475. // now write the generated text...
  476.   if ( strHasCRLF = strstr( ptrTokenNext, "\n" ) )
  477.     *strHasCRLF = '\0' ;               // remove newline
  478.  
  479. // note that hardspace  chars must be the first character(s) of a command arg
  480.   if ( hardspace == *ptrTokenNext )
  481.   {
  482.      ptrTmp = ptrTokenNext ;           // don't modify ptrTokenNext
  483.      while( hardspace == *ptrTmp )     // convert hardspace characters to spaces
  484.      {
  485.        *ptrTmp = ' ' ;
  486.        ptrTmp++ ;
  487.      }
  488.   }
  489.  
  490. // certain commands, like /fs CANNOT have a space between it and its numeric arg
  491.   if (TRUE == bNoSpace)
  492.      rc = fprintf(flOutput,"%s%s%s\n",strTagHeader,ptrTokenNext,strTagTrailer) ;
  493.   else
  494.      rc = fprintf(flOutput,"%s %s%s\n",strTagHeader,ptrTokenNext,strTagTrailer) ;
  495.  
  496.   if (rc < 0)
  497.   {
  498.      printf("RTFHELP:  error from fprintf\n") ;
  499.      exit(LIBRARY_ERROR) ;
  500.   }
  501.  
  502.   return RC_OK ;
  503. }
  504.  
  505. // *Microsoft Corporation.  Programmer's Reference, Volume 4:  Resources.
  506. //  (Redmond, Washington:  Microsoft Corporation, 1992), Chapter 15.
  507.